package system

import (
	"bottle/conf"
	"bottle/global"
	"bottle/model/common/response"
	"bottle/model/system"
	systemReq "bottle/model/system/request"
	systemRes "bottle/model/system/response"
	"bottle/utils"
	"context"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v8"
	"github.com/qiniu/go-sdk/v7/auth"
	"github.com/qiniu/go-sdk/v7/storage"
	sts "github.com/tencentyun/qcloud-cos-sts-sdk/go"
	"go.uber.org/zap"
	"time"
)

func (b *BaseApi) Login(c *gin.Context) {
	var req systemReq.Login
	err := c.ShouldBind(&req)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(req, utils.LoginVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	code2SessionReq := &systemReq.Code2SessionRequest{
		AppId:  conf.Appid,
		Secret: conf.Secret,
		Code:   req.Code,
		ACode:  "",
		JsCode: req.Code,
		GrantType: "authorization_code",
	}
	code2SessionResp, err := userService.Code2Session(c, code2SessionReq)

	if err != nil {
		res := &systemReq.LoginResponse{
			ErrCode: -1,
			ErrMsg:  err.Error(),
			Token:   "",
		}
		response.OkWithData(res, c)
		return
	}

	//if code2SessionResp.ErrNo != 0 {
	//	res := &systemReq.LoginResponse{
	//		ErrCode: -1,
	//		ErrMsg:  code2SessionResp.ErrTips,
	//		Token:   "",
	//	}
	//	response.OkWithData(res, c)
	//	return
	//}

	var user = system.User{OpenID: code2SessionResp.Openid, UnionID: code2SessionResp.UnionId}
	err, u := userService.Register(user)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	b.tokenNext(c, u)
	return
}

// 登录以后签发jwt
func (b *BaseApi) tokenNext(c *gin.Context, user system.User) {
	j := &utils.JWT{SigningKey: []byte(global.GVA_CONFIG.JWT.SigningKey)} // 唯一签名
	claims := j.CreateClaims(systemReq.BaseClaims{
		UUID: user.UUID,
		ID:   user.ID,
		//NickName:    user.NickName,
		Username: user.Username,
		//AuthorityId: user.AuthorityId,
	})
	token, err := j.CreateToken(claims)
	if err != nil {
		global.GVA_LOG.Error("获取token失败!", zap.Error(err))
		response.FailWithMessage("获取token失败", c)
		return
	}
	if !global.GVA_CONFIG.System.UseMultipoint {
		response.OkWithDetailed(systemRes.LoginResponse{
			User:      user,
			Token:     token,
			ExpiresAt: claims.StandardClaims.ExpiresAt * 1000,
		}, "登录成功", c)
		return
	}

	if err, jwtStr := jwtService.GetRedisJWT(user.Username); err == redis.Nil {
		if err := jwtService.SetRedisJWT(token, user.Username); err != nil {
			global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err))
			response.FailWithMessage("设置登录状态失败", c)
			return
		}
		response.OkWithDetailed(systemRes.LoginResponse{
			User:      user,
			Token:     token,
			ExpiresAt: claims.StandardClaims.ExpiresAt * 1000,
		}, "登录成功", c)
	} else if err != nil {
		global.GVA_LOG.Error("设置登录状态失败!", zap.Error(err))
		response.FailWithMessage("设置登录状态失败", c)
	} else {
		var blackJWT system.JwtBlacklist
		blackJWT.Jwt = jwtStr
		if err := jwtService.JsonInBlacklist(blackJWT); err != nil {
			response.FailWithMessage("jwt作废失败", c)
			return
		}
		if err := jwtService.SetRedisJWT(token, user.Username); err != nil {
			response.FailWithMessage("设置登录状态失败", c)
			return
		}
		response.OkWithDetailed(systemRes.LoginResponse{
			User:      user,
			Token:     token,
			ExpiresAt: claims.StandardClaims.ExpiresAt * 1000,
		}, "登录成功", c)
	}
}

func (b *BaseApi) SetUserInfo(c *gin.Context) {
	var req systemReq.SetUserInfoReq
	err := c.ShouldBind(&req)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(req, utils.SetUserInfoVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	var user = system.User{Username: req.Username, Avatar: req.Avatar, Gender: req.Gender, Region: req.Region}
	err = global.GVA_DB.Model(&system.User{}).Where("id = ?", req.ID).Updates(user).Error
	if err != nil {
		response.FailWithMessage("修改失败", c)
		return
	}
	var userInfo systemRes.UserInfoRes
	global.GVA_DB.Model(&system.User{}).Where("id = ?", req.ID).First(&userInfo)
	response.OkWithData(userInfo, c)
	return
}

func (b *BaseApi) SetUserAddress(c *gin.Context) {
	var req systemReq.SetUserAddressReq
	err := c.ShouldBind(&req)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(req, utils.SetUserAddressVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	//限制每天只能修改一次地址
	now := time.Now()
	nextDay := time.Date(now.Year(), now.Month(), now.Day()+1, 0, 0, 0, 0, time.Local)
	duration := nextDay.Sub(now)
	cacheKey := fmt.Sprintf("setUserAddress@%d", req.ID)
	setResult := global.GVA_REDIS.SetNX(context.Background(), cacheKey, 1, duration)
	if setResult.Val() == false {
		response.FailWithMessage("一天只能设置一次地址哦", c)
		return
	}

	var user = system.User{Region: req.Region, ProvinceCode: req.ProvinceCode, CityCode: req.CityCode}
	err = global.GVA_DB.Model(&system.User{}).Where("id = ?", req.ID).Updates(user).Error
	if err != nil {
		response.FailWithMessage("修改失败", c)
		return
	}
	var userInfo systemRes.UserInfoRes
	global.GVA_DB.Model(&system.User{}).Where("id = ?", req.ID).First(&userInfo)
	response.OkWithData(userInfo, c)
	return
}

func (b *BaseApi) GetUserInfo(c *gin.Context) {
	var req systemReq.IDReq
	err := c.ShouldBind(&req)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(req, utils.IDVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	var user systemRes.UserInfoRes
	err = global.GVA_DB.Model(&system.User{}).Where("id = ?", req.ID).First(&user).Error
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	response.OkWithData(user, c)
	return
}

func (b *BaseApi) GetUserInfoByUUID(c *gin.Context) {
	//uuid := utils.GetUserUuid(c)
	var req systemReq.UUIDReq
	err := c.ShouldBind(&req)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(req, utils.UUIDVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	if err, ReqUser := userService.GetUserInfoByUUID(req.UUID); err != nil {
		global.GVA_LOG.Error("获取失败!", zap.Error(err))
		response.FailWithMessage("获取失败", c)
	} else {
		response.OkWithData(ReqUser, c)
	}
}

// goEasy webHook同步历史消息  todo: 后续需要增加校验
func (b *BaseApi) SynchronousMessage(c *gin.Context) {
	var req systemReq.SynchronousMessageRequest
	err := c.ShouldBind(&req)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}
	err = utils.Verify(req, utils.SyncMessageVerify)
	if err != nil {
		response.FailWithMessage(err.Error(), c)
		return
	}

	var messages []system.MessageFromJson
	err = json.Unmarshal([]byte(req.Content), &messages)
	if err != nil {
		global.GVA_LOG.Error(err.Error())
		response.Fail(c)
		return
	}
	var addMsg []system.Message
	for _, v := range messages {
		payload, _ := json.Marshal(v.Payload)
		msg := system.Message{
			MessageID:  v.MessageID,
			Type:       v.Type,
			SenderID:   v.SenderID,
			ReceiverID: v.ReceiverID,
			Payload:    string(payload),
			Timestamp:  time.Unix(0, v.Timestamp*1e6),
		}
		addMsg = append(addMsg, msg)
	}
	global.GVA_DB.Create(addMsg)
	response.OkWithData(addMsg, c)
	return
}

func (b *BaseApi) GetAuthor(c *gin.Context) {
	appid := "1302606804"
	bucket := "goeasy-im2-1302606804"
	client := sts.NewClient(
		"AKIDtfGmVlt1Kk2CweR9kN4hO0iN6xkbaaea",
		"vhK4rgXJwcAYs4772kebUPGwSp8IfcSA",
		nil,
		//sts.Host("sts.internal.tencentcloudapi.com"), // 设置域名, 默认域名sts.tencentcloudapi.com
		//sts.Scheme("https"),      // 设置协议, 默认为https，公有云sts获取临时密钥不允许走http，特殊场景才需要设置http
	)
	// 策略概述 https://cloud.tencent.com/document/product/436/18023
	opt := &sts.CredentialOptions{
		DurationSeconds: int64(time.Hour.Seconds()),
		Region:          "ap-guangzhou",
		Policy: &sts.CredentialPolicy{
			Statement: []sts.CredentialPolicyStatement{
				{
					// 密钥的权限列表。简单上传和分片需要以下的权限，其他权限列表请看 https://cloud.tencent.com/document/product/436/31923
					Action: []string{
						// 简单上传
						"name/cos:PostObject",
						"name/cos:PutObject",
						// 分片上传
						"name/cos:InitiateMultipartUpload",
						"name/cos:ListMultipartUploads",
						"name/cos:ListParts",
						"name/cos:UploadPart",
						"name/cos:CompleteMultipartUpload",
					},
					Effect: "allow",
					Resource: []string{
						// 这里改成允许的路径前缀，可以根据自己网站的用户登录态判断允许上传的具体路径，例子： a.jpg 或者 a/* 或者 * (使用通配符*存在重大安全风险, 请谨慎评估使用)
						// 存储桶的命名格式为 BucketName-APPID，此处填写的 bucket 必须为此格式
						"qcs::cos:ap-guangzhou:uid/" + appid + ":" + bucket + "/exampleobject",
					},
					// 开始构建生效条件 condition
					// 关于 condition 的详细设置规则和COS支持的condition类型可以参考https://cloud.tencent.com/document/product/436/71306
					Condition: map[string]map[string]interface{}{
						"ip_equal": map[string]interface{}{
							"qcs:ip": []string{
								"10.217.182.3/24",
								"111.21.33.72/24",
							},
						},
					},
				},
			},
		},
	}
	// case 1 请求临时密钥
	res, err := client.GetCredential(opt)
	if err != nil {
		response.Fail(c)
		global.GVA_LOG.Error(err.Error())
		return
	}
	response.OkWithData(res, c)
	return
}

func (b *BaseApi) GetQiNiuAuthor(c *gin.Context) {
	accessKey := "CgYxgFuRARB6c4pRui6Jpc31yA6tCaQW-IGkCB6Z"
	secretKey := "WEjx2_B8LybLjysuqAk1Rk010SO90YqcbF5ApWhb"

	bucket := "spinachead"
	putPolicy := storage.PutPolicy{
		Scope: bucket,
	}
	mac := auth.New(accessKey, secretKey)
	upToken := putPolicy.UploadToken(mac)
	response.OkWithData(upToken, c)
	return
}
